use bevy_ecs::{
    entity,
    prelude::{Component, Schedule, World},
    schedule::{Stage, SystemStage},
};
use egui::epaint::ahash::{HashMap, HashMapExt};
use rapier2d::{
    na::Vector2,
    prelude::{ColliderBuilder, Real, RigidBodyBuilder, RigidBodyType, Vector},
};
use uuid::Uuid;

use crate::{
    core::pool::{Handle, Pool},
    function::{script::script_engine::AliceScriptEngine, utils::io::AliceUtils},
    math::Matrix4f,
    AliceContext,
};

use super::{
    camera::{Camera, SceneCamera},
    components::{
        CameraComponent, Collider2DComponent, IdComponent, Rigidbody2DComponent, ScriptComponent,
        SpriteRendererComponent, TagComponent, Transform, TransformComponent,
    },
    entity::Entity,
    system::render_sprite,
    world::AlicePhysicsWorld,
};

#[derive(serde::Serialize, serde::Deserialize)]
pub struct EntityDescriptor {
    pub name: String,
    pub id: Uuid,
    pub transform: Transform,
    pub sprite: Option<SpriteRendererComponent>,
    pub rigidbody2d: Option<Rigidbody2DComponent>,
    pub collider2d: Option<Collider2DComponent>,
    pub children: Vec<EntityDescriptor>,
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct PhysicalWorldDescriptor {
    pub gravity: Vector<Real>,
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct SceneDescriptor {
    pub name: String,
    pub id: Uuid,
    pub physical_setting: PhysicalWorldDescriptor,
    pub entities: Vec<String>,
}

use once_cell::sync::OnceCell;

static mut INSTANCE: OnceCell<Scene> = OnceCell::new();

static mut SCENE_INSTANCE: OnceCell<SceneServer> = OnceCell::new();

pub struct SceneServer {
    active: Handle<Scene>,
    scene_pool: Pool<Scene>,
}

impl SceneServer {
    pub fn new()-> Self {
        SceneServer { active: Handle::NONE, scene_pool: Pool::new() }
    }

    pub fn get_active(&self) -> &Scene {
        &self.scene_pool.borrow(self.active)
    }

    pub fn get_active_scene_mut(&mut self) -> &mut Scene {
        self.scene_pool.borrow_mut(self.active)
    }

    pub fn set_active_scene(&mut self, handle: Handle<Scene>) {
        self.active = handle
    }

    pub fn send(&mut self, scene:Scene) -> Handle<Scene> {
        self.scene_pool.spawn(scene)
    }

    pub fn get_scene(&self, handle: Handle<Scene>) -> &Scene {
        self.scene_pool.borrow(handle)
    }

    pub fn get_scene_mut(&mut self, handle: Handle<Scene>) -> &mut Scene {
        self.scene_pool.borrow_mut(handle)
    }

    pub fn get_scene_two_mut(&mut self, handle1: Handle<Scene>,handle2: Handle<Scene>) -> (&mut Scene,&mut Scene) {
        self.scene_pool.borrow_two_mut((handle1,handle2))
    }


}

impl SceneServer {
    pub fn get_server() -> &'static SceneServer {
        unsafe { SCENE_INSTANCE.get().expect("SceneServer is not initialized") }
    }

    pub fn get_server_mut() -> &'static mut SceneServer {
        unsafe { SCENE_INSTANCE.get_mut().expect("SceneServer is not initialized") }
    }


    pub fn initialize_scene_server(server:SceneServer) {
        unsafe { SCENE_INSTANCE.set(server); }
    }
}

pub struct ScheduleWrap(Schedule);

impl std::fmt::Debug for ScheduleWrap {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_tuple("ScheduleWrap").finish()
    }
}

impl std::ops::Deref for ScheduleWrap {
    type Target = Schedule;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl std::ops::DerefMut for ScheduleWrap {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

#[derive(Debug)]
pub struct Scene {
    id: Uuid,
    pub world: World,
    pub name:String,
    pub schedule: ScheduleWrap,
    pub root: entity::Entity,
    pub uid_entity_map: HashMap<Uuid, Entity>,
    pub primary_camera: Option<entity::Entity>,
    // pub script_engine:Option<AliceScriptEngine>,
}

// impl Scene {
//     pub fn active_scene() -> &'static Scene {
//         unsafe { INSTANCE.get().expect("Active Scene is not initialized") }
//     }

//     pub fn get_active_scene_mut() -> &'static mut Scene {
//         unsafe { INSTANCE.get_mut().expect("Active Scene is not initialized") }
//     }

//     pub fn set_active_scene(scene: Scene) {
//         match unsafe { INSTANCE.set(scene) } {
//             Ok(_) => {}
//             Err(_) => {}
//         }
//     }
// }

impl Scene {
    pub fn new(name:&str) -> Self {
        let mut world = World::new();

        world.insert_resource::<AlicePhysicsWorld>(AlicePhysicsWorld::new());

        let mut schedule = Schedule::default();
        schedule.add_stage("render", SystemStage::parallel().with_system(render_sprite));
        let mut entity_map = HashMap::new();
        let id = Uuid::new_v4();
        let handle = world
            .spawn()
            .insert(IdComponent { id })
            .insert(TagComponent {
                tag: "root".to_owned(),
            })
            .id();

        let root = Entity::new(handle);

        entity_map.insert(id, root.clone());

        Self {
            id: Uuid::new_v4(),
            world,
            name:name.to_owned(),
            schedule: ScheduleWrap(schedule),
            root: handle,
            uid_entity_map: entity_map,
            primary_camera: None,
            // script_engine:None
        }
    }

    pub fn create_entity(&mut self, name: &str) -> Entity {
        self.create_entity_with_uuid(Uuid::new_v4(), name)
    }
    pub fn create_entity_with_uuid(&mut self, uuid: Uuid, name: &str) -> Entity {
        let handle = self.world.spawn().id();

        let mut entity = Entity::new(handle);

        self.uid_entity_map.insert(uuid, entity.clone());
        entity.add_component(self, IdComponent { id: uuid });
        entity.add_component(
            self,
            TagComponent {
                tag: if name.is_empty() {
                    "GameObject".to_owned()
                } else {
                    name.to_owned()
                },
            },
        );

        entity
    }

    pub fn add_system(&mut self, name: &'static str, stage: SystemStage) -> &mut Self {
        self.schedule.add_stage(name, stage);
        self
    }

    pub fn add_system_before(
        &mut self,
        target: &'static str,
        name: &'static str,
        stage: SystemStage,
    ) -> &mut Self {
        self.schedule.add_stage_before(target, name, stage);
        self
    }

    pub fn add_system_after(
        &mut self,
        target: &'static str,
        name: &'static str,
        stage: SystemStage,
    ) -> &mut Self {
        self.schedule.add_stage_after(target, name, stage);
        self
    }

    pub fn tick(&mut self, dt: f64) {
        // pre tick

        if let Some(mut world) = self.world.get_resource_mut::<AlicePhysicsWorld>() {
            world.tick();
        }

        self.schedule.run(&mut self.world);
    }

    pub fn pre_tick(&mut self, dt: f64, ctx: AliceContext) {
        self.update_world_transform();

        self.update_script(dt, ctx);
    }

    pub fn get_camera_view(&self) -> Matrix4f {
        let camera = self.world.resource::<SceneCamera>();
        Matrix4f::webgl_to_wgpu(camera.get_view_projection())
    }

    pub fn get_entity(&self, entity: &entity::Entity) -> Option<&Entity> {
        let id = self.world.get::<IdComponent>(*entity).unwrap().id;
        self.uid_entity_map.get(&id)
    }

    pub fn get_entity_mut(&mut self, entity: &entity::Entity) -> Option<&mut Entity> {
        let id = self.world.get::<IdComponent>(*entity).unwrap().id;
        self.uid_entity_map.get_mut(&id)
    }

    pub fn update_world_transform(&mut self) {
        self.update_node_transform(&self.root.clone(), Matrix4f::identity())
    }

    pub fn update_node_transform(&mut self, entity: &entity::Entity, parent_transform: Matrix4f) {
        let world_transform;
        if let Some(mut transform) = self.world.get_mut::<TransformComponent>(*entity) {
            transform.world_transform_base = parent_transform;

            world_transform = transform.get_transform();
        } else {
            world_transform = parent_transform;
        }

        let id = self.world.get::<IdComponent>(*entity).unwrap().id;
        let entity = self.uid_entity_map.get(&id).unwrap();

        let entities = entity
            .children
            .iter()
            .map(|e| e.clone())
            .collect::<Vec<entity::Entity>>();

        for entity in entities {
            self.update_node_transform(&entity, world_transform)
        }
    }

    fn update_script(&mut self, dt: f64, ctx: AliceContext) {
        let mut script_engine = ctx.script();

        let mut query = self.world.query::<(&IdComponent, &ScriptComponent)>();
        for (id, script) in query.iter_mut(&mut self.world) {
            script_engine.invoke_update(id.id, dt);
        }
    }

    pub fn check_primary_camera(&self) -> bool {
        if let Some(entity) = self.primary_camera {
            let entity_ref = self.world.entity(entity);
            return entity_ref.contains::<CameraComponent>();
        }

        false
    }
}

/// runtime scene
impl Scene {
    pub fn get_component<T: Component>(&self, id: Uuid) -> Option<&T> {
        let entity = self.uid_entity_map.get(&id).unwrap();
        entity.get_component::<T>(self)
    }
}

/// Copy scene
impl Scene {
    pub fn copy_from(&mut self, rhs: &Scene) {
        self.world.clear_entities();

        self.world
            .insert_resource::<AlicePhysicsWorld>(AlicePhysicsWorld::new());
        self.primary_camera = rhs.primary_camera;
        self.root = self.copy_entity(rhs, rhs.root, None);
    }

    pub fn copy_entity(
        &mut self,
        rhs: &Scene,
        entity: entity::Entity,
        parent: Option<entity::Entity>,
    ) -> entity::Entity {
        let rhs_entity = rhs.get_entity(&entity).unwrap();
        let id = Uuid::new_v4();
        let mut entity_node = self.create_entity_with_uuid(
            id,
            &rhs_entity.get_component::<TagComponent>(rhs).unwrap().tag,
        );
        if let Some(transform) = rhs_entity.get_component::<TransformComponent>(rhs) {
            entity_node.add_component(self, transform.clone());
        }
        if let Some(script) = rhs_entity.get_component::<ScriptComponent>(rhs) {
            entity_node.add_component(self, script.clone());
        }

        if let Some(sprite) = rhs_entity.get_component::<SpriteRendererComponent>(rhs) {
            entity_node.add_component(self, sprite.clone());
        }

        if let Some(rigidbody) = rhs_entity.get_component::<Rigidbody2DComponent>(rhs) {
            entity_node.add_component(self, rigidbody.clone());
        }

        if let Some(collider) = rhs_entity.get_component::<Collider2DComponent>(rhs) {
            entity_node.add_component(self, collider.clone());
        }

        entity_node.parent = parent;

        let mut children = Vec::new();
        for e in rhs_entity.children.iter() {
            let handle = self.copy_entity(rhs, *e, Some(entity_node.handle));
            children.push(handle);
        }
        entity_node.children = children;
        let handle = entity_node.handle;
        self.uid_entity_map.insert(id, entity_node);
        handle
    }
}

/// prepare scene data
impl Scene {
    pub fn prepare_scene(&mut self, ctx: AliceContext) {
        let mut script_engine = ctx.script();
        self.instance_entity(&self.root.clone(), &mut script_engine);

        // create scene primary camera
        println!("prepare_scene111");
        if self.check_primary_camera() {
            let camera_ref = self.world.get_entity(self.primary_camera.unwrap()).unwrap();
            let camera = camera_ref.get::<CameraComponent>().unwrap();
            let transform = camera_ref.get::<TransformComponent>().unwrap();

            let primary_camera = match camera.camera_ty {
                super::camera::CameraType::Orthographic => {
                    let mut primary_camera = SceneCamera::new_with_orthographic(
                        -camera.aspect_ratio * 1.0,
                        camera.aspect_ratio * 1.0,
                        -1.0,
                        1.0,
                    );
                    let view = transform.get_transform().inverse();
                    primary_camera.set_view(view);
                    primary_camera
                }
                super::camera::CameraType::Perspective => {
                    let mut primary_camera = SceneCamera::new_with_perspective(
                        camera.perspective_fovy,
                        camera.aspect_ratio,
                        camera.clip_near,
                        camera.clip_far,
                    );
                    let view = transform.get_transform().inverse();
                    primary_camera.set_view(view);
                    primary_camera
                }
            };
            println!("prepare_scene");
            self.world.insert_resource::<SceneCamera>(primary_camera);
        }
    }

    pub fn instance_entity(
        &mut self,
        entity: &entity::Entity,
        script_engine: &mut AliceScriptEngine,
    ) {
        let entity_node = Entity::new(*entity);

        // rigidbody2d
        if entity_node.has_component::<ScriptComponent>(self) {
            let script = self
                .world
                .get_mut::<ScriptComponent>(*entity)
                .unwrap()
                .clone();

            let entity_ref = self.world.get_entity(*entity).unwrap();

            script_engine.instance_script(
                Entity::new(*entity),
                &self,
                &script.path,
                &script.class_name,
            );
        }

        // rigidbody2d
        if entity_node.has_component::<Rigidbody2DComponent>(self) {
            let rg = self
                .world
                .get_mut::<Rigidbody2DComponent>(*entity)
                .unwrap()
                .clone();

            let entity_ref = self.world.get_entity(*entity).unwrap();
            let transform = entity_ref.get::<TransformComponent>().unwrap();
            let position = transform.translation.xy();
            let mut world = self.world.get_resource_mut::<AlicePhysicsWorld>().unwrap();

            let body = match rg.rb_type {
                RigidBodyType::Fixed => RigidBodyBuilder::fixed(),
                RigidBodyType::Dynamic => RigidBodyBuilder::dynamic(),
                RigidBodyType::KinematicPositionBased => {
                    RigidBodyBuilder::kinematic_position_based()
                }
                RigidBodyType::KinematicVelocityBased => {
                    RigidBodyBuilder::kinematic_velocity_based()
                }
            }
            .translation(Vector2::new(position.x, position.y))
            .additional_mass(rg.mass)
            .ccd_enabled(rg.ccd)
            .build();

            let body_handle = world.rigid_body_set.insert(body);
            println!("body_handle = {:?}", body_handle);
            self.world
                .get_mut::<Rigidbody2DComponent>(*entity)
                .unwrap()
                .body_handle = body_handle;
        }

        // collider2d

        if entity_node.has_component::<Collider2DComponent>(self)
            && entity_node.has_component::<Rigidbody2DComponent>(self)
        {
            let _ci = self
                .world
                .get_mut::<Collider2DComponent>(*entity)
                .unwrap()
                .clone();

            let entity_ref = self.world.get_entity(*entity).unwrap();
            let rigidbody = entity_ref.get::<Rigidbody2DComponent>().unwrap();
            let body_handle = rigidbody.body_handle;
            let mut world = self.world.get_resource_mut::<AlicePhysicsWorld>().unwrap();

            let collider = ColliderBuilder::ball(0.5).restitution(0.7).build();

            let handle = world.set_collider(collider, body_handle);

            self.world
                .get_mut::<Collider2DComponent>(*entity)
                .unwrap()
                .handle = handle;
        }

        let id = entity_node.get_component::<IdComponent>(self).unwrap();
        let entity = self.uid_entity_map.get(&id.id).unwrap();

        let entities = entity
            .children
            .iter()
            .map(|e| e.clone())
            .collect::<Vec<entity::Entity>>();

        for entity in entities {
            self.instance_entity(&entity, script_engine)
        }
    }
}

/// Serialize And Deserialize

impl Scene {
    pub fn serialize(&self) {
        let id = self.world.get::<IdComponent>(self.root).unwrap().id;
        let root = self.uid_entity_map.get(&id).unwrap();

        let entities = root
            .children
            .iter()
            .map(|entity| self.serialize_entity(*entity))
            .collect::<Vec<String>>();
        let world = self.world.get_resource::<AlicePhysicsWorld>().unwrap();
        let scene_descriptor = SceneDescriptor {
            name: "Test Scene".to_owned(),
            id: self.id,
            physical_setting: PhysicalWorldDescriptor {
                gravity: world.gravity,
            },
            entities,
        };

        let root = std::env::current_dir().unwrap();
        let file_path = root.join("assets/scene");

        AliceUtils::write_text_file(
            file_path,
            &format!("scene_{}.json", self.id),
            &serde_json::to_string(&scene_descriptor).unwrap(),
        )
        .unwrap();
    }

    pub fn serialize_entity(&self, entity: entity::Entity) -> String {
        let entity_ref = self.world.get_entity(entity).unwrap();
        let id = entity_ref.get::<IdComponent>().unwrap().id;
        let name = entity_ref.get::<TagComponent>().unwrap().clone().tag;

        let transform = entity_ref.get::<TransformComponent>().unwrap().clone();
        let transform = Transform {
            translation: transform.translation,
            rotation: transform.rotation,
            scale: transform.scale,
        };
        let sprite = if let Some(sprite) = entity_ref.get::<SpriteRendererComponent>() {
            Some(sprite.clone())
        } else {
            None
        };

        let rigidbody2d = if let Some(rigidbody2d) = entity_ref.get::<Rigidbody2DComponent>() {
            Some(rigidbody2d.clone())
        } else {
            None
        };

        let collider2d = if let Some(collider2d) = entity_ref.get::<Collider2DComponent>() {
            Some(collider2d.clone())
        } else {
            None
        };
        let entity = self.uid_entity_map.get(&id).unwrap();
        let children = entity
            .children
            .iter()
            .map(|entity| self.serialize_child_entity(*entity))
            .collect::<Vec<EntityDescriptor>>();

        let entity_descriptor = serde_json::to_string(&EntityDescriptor {
            id,
            name,
            transform,
            sprite,
            rigidbody2d,
            collider2d,
            children,
        })
        .unwrap();
        // alice2d_input\assets\scene

        let root = std::env::current_dir().unwrap();
        let file_path = root.join("assets/scene");

        let full_path = file_path.clone().join(&format!("entity_{}.json", id));
        let full_path = full_path.as_os_str().to_str().unwrap().to_owned();
        AliceUtils::write_text_file(
            file_path,
            &format!("entity_{}.json", id),
            &entity_descriptor,
        )
        .unwrap();
        // write file
        full_path
    }

    pub fn serialize_child_entity(&self, entity: entity::Entity) -> EntityDescriptor {
        let entity_ref = self.world.get_entity(entity).unwrap();

        let name = entity_ref.get::<TagComponent>().unwrap().clone().tag;
        let id = entity_ref.get::<IdComponent>().unwrap().id;
        let transform = entity_ref.get::<TransformComponent>().unwrap().clone();
        let transform = Transform {
            translation: transform.translation,
            rotation: transform.rotation,
            scale: transform.scale,
        };
        let sprite = if let Some(sprite) = entity_ref.get::<SpriteRendererComponent>() {
            Some(sprite.clone())
        } else {
            None
        };

        let rigidbody2d = if let Some(rigidbody2d) = entity_ref.get::<Rigidbody2DComponent>() {
            Some(rigidbody2d.clone())
        } else {
            None
        };

        let collider2d = if let Some(collider2d) = entity_ref.get::<Collider2DComponent>() {
            Some(collider2d.clone())
        } else {
            None
        };
        let entity = self.uid_entity_map.get(&id).unwrap();
        let children = entity
            .children
            .iter()
            .map(|entity| self.serialize_child_entity(*entity))
            .collect::<Vec<EntityDescriptor>>();

        EntityDescriptor {
            name,
            id,
            transform,
            sprite,
            rigidbody2d,
            collider2d,
            children,
        }
    }

    pub fn deserialize(path: &str) -> Self {
        let file = AliceUtils::read_text_file_unwrap(path).unwrap();
        match serde_json::from_str::<SceneDescriptor>(&file) {
            Ok(scene_descriptor) => {
                let entities = scene_descriptor
                    .entities
                    .iter()
                    .map(|p| {
                        let str = AliceUtils::read_text_file_unwrap(p).unwrap();
                        let entity_descriptor: EntityDescriptor =
                            serde_json::from_str(&str).unwrap();
                        entity_descriptor
                    })
                    .collect::<Vec<EntityDescriptor>>();

                let mut scene = Scene::new("deserialize");

                scene.id = scene_descriptor.id;

                let mut root = Entity::new(scene.root);

                entities.iter().for_each(|entity| {
                    scene.deserialize_entity(entity, &mut root);
                });

                scene.uid_entity_map.insert(root.get_uuid(&scene), root);

                scene
            }
            Err(_) => {
                println!("场景文件损坏！将使用默认场景");
                let config = Self::new("default");

                config
            }
        }
    }

    pub fn deserialize_entity(
        &mut self,
        entity_descriptor: &EntityDescriptor,
        parent: &mut Entity,
    ) {
        let tag = TagComponent {
            tag: entity_descriptor.name.clone(),
        };
        let id = IdComponent {
            id: entity_descriptor.id,
        };
        let transform = TransformComponent {
            translation: entity_descriptor.transform.translation,
            rotation: entity_descriptor.transform.rotation,
            scale: entity_descriptor.transform.scale,
            world_transform_base: Default::default(),
        };

        let mut entity = self.world.spawn();
        entity.insert(tag).insert(id).insert(transform);

        if let Some(sprite) = &entity_descriptor.sprite {
            entity.insert(sprite.clone());
        }
        if let Some(rigidbody2d) = &entity_descriptor.rigidbody2d {
            entity.insert(rigidbody2d.clone());
        }
        if let Some(collider2d) = &entity_descriptor.collider2d {
            entity.insert(collider2d.clone());
        }

        let entity = entity.id();

        let mut entity_instance = Entity::new(entity);
        parent.add_child(&mut entity_instance);

        entity_descriptor
            .children
            .iter()
            .for_each(|e| self.deserialize_entity(e, &mut entity_instance));

        self.uid_entity_map
            .insert(entity_descriptor.id, entity_instance);
    }
}

#[test]
fn test_scene() {
    // let mut scene = Scene::new();

    // // This system moves each entity with a Position and Velocity component
    // fn print_tag(query: Query<&TagComponent>) {
    //     for tag in &query {
    //         println!("tag = {:?}", tag);
    //     }
    // }

    // scene.add_system("update", SystemStage::parallel().with_system(print_tag));
    // let mut entity1 = scene.create_entity("entity0");

    // entity1.add_component(TransformComponent::new(Vector3f::new(10.0, 0.0, 0.0)));

    // let entity2 = scene.create_entity("entity1");

    // scene.tick();
    // scene.tick();
}
